#ifndef __CACTIVITY_H
#define __CACTIVITY_H

//------------------------------------------------------------
//Input part
//------------------------------------------------------------
//The base of all Input
class CInput
{
  public:
    virtual void dispatch(cInputMap* aMap) = 0;
};

//a Derived input type
//class
class CInputKeyboard : public CInput
{
    void Dispatch(CInputMap* aMap)
    {
      aMap->HandleInput(*this);
    }
};

//The input engine
class CInputMap
{
  public:
    void HandleInput(InputKeyboard& aInput)
    {
      CKeyEventHandler* pHandler = GetKeyHandler();
      if (pHandler)
      {
        pHandler->iKeyDeviceAll.Fire(aInput);
      }
    }

  public:
    virtual CKeyEventHandler* GetKeyHandler()
    {
      return NULL;
    }
};

class CKeyEventHandler
{
  protect:       //The Delegate
    Delegate    iKeyDevice;

  protect:
    virtual bool onKeyEvent(aEvent);
};

class cscreeneventhandler
{
  public:       //The Delegate
    Delegate    iScreenDevice;

  public:
    virtual bool onScreenEvent(aEvent);
};

//------------------------------------------------------------
//view part
//------------------------------------------------------------

//Base class of all widget
class View
{
  public:       //children manage
    void AddChild(View* const aChild);
    void RemoveChild(View* const aChild);

  public:       //render func
    void SetPosition(const TPosition& aPosition);

    void Render() const
    {
      std::for_each(m_Children.begin(),
                    m_Children.End(),
                    ViewRenderer());
    }
};

//The Render engine
class ViewRenderer
{
  public:
    inline void operator() (View const * aView) const
    {
      aView->Render(iViewContex);
    }
};

//The view contex
class ViewContex 
{
};

//------------------------------------------------------------
//model part.The activity change the model, and model update
//its related view to show the change
//------------------------------------------------------------

//base class for all model
class CModel
{
  public:
};

//------------------------------------------------------------
//layout part.Not only the viewManager care about the layout,
//the activity alse need to know it, becase view's position is
//important when deal with the mouse input envents.
//------------------------------------------------------------

//base class 
class RLayout
{
};

//------------------------------------------------------------
//state part
//------------------------------------------------------------

class CActivityManager : public CInputMap
{
  public:
    void AddActivity(CActivity* aActivity);
    void RemoveActivity(CActivity* aActivity);

  public:
    virtual CKeyEventHandler* GetKeyHandler()
    {
      return CurrentActivity();
    }

  private:
    CActivity* CurrentActivity();
};


class CWindowProxy
{
  public:       //menu funcs
    virtual void OnMenu();
    virtual virtual void OnCreateMenu(Menu menu);
    virtual void CloseMenu();
    virtual void OnSelectMenuItem();

  public:       //Dialog funcs
    virtual void OnCreateDialog(int id);
    virtual void OnShowDialog(TInt aId, CDialog* aDialog);
    virtual void RemoveDialog(); 

  public:       //view funcs
    void SetContentView(CWindow* aWindow);
};

class CState
{
  public
    void OnExit();
    virtual void onCreate(); 
    virtual void onStart(); 
    virtual void onResume(); 
    virtual void onPause(); 
    virtual void onStop(); 
    virtual void onDestroy(); 

  public:
    virtual void update();
};

class CActivity : 
  public CKeyEventHandler, 
  public CScreenEventHandler
  public CWindowProxy
  public CState
{
  public:
    virtual void DefaultInit();

  public:       //activity funcs
    void StartActivity(TActiviyOption aOp, CActivityFactory aFactory);

    void OnActiviyResult(TIntent aIntent);
};

void 
CActivity::
OnDefaultInit()
{
  iKeyInputButton.Bind(this, OnInputMethodChange);
  iKeyDevice0.Bind(this, Exit());
  iKeyDevice1.Bind(this, OnMenuButton());
}

void
CActivity::
ConstructL()
{
  OnDefaultInit();
  OnCreate();
  OnStart();
  OnResume();
  Update();
}

//Default implementation
void
CActivity::
OnCreate()
{
  //create all widgets
  iHead = CHead::NewL();

  iModelList = CModelList::NewL();
  iMainList = CMainList::NewL(iModelList);

  iMenu = CMenu::NewL();

  //create the layout.
  //The layout manage the id and position of widgets
  RListLayout layout(TPosition(0, 0, 240, 320));
  layout.AddPosition(CMainWindow::EHead, TPosition(0, 300, 240, 320));
  layout.AddPosition(CMainWindow::ETop, TPosition(0, 20, 240, 300));
  layout.AddPosition(CMainWindow::EBottom, TPosition(0, 0, 240, 20));

  //create the main window
  iMainWindow = CMainWindow::NewL(layout);

  aMainWindow->AddWidget(iHead, aPos.NextPosition());
  aMainWindow->AddWidget(iMainList aPos.NextPosition());
  aMainWindow->AddWidget(iMenubar, aPos.NextPosition());

  //how is the reloation active between activity and window?
  SetiMainWindow(iMainWindow);
  OnFocusChange(iMainList);
}

void 
CActivity::
ProcessEvent()
{
  switch()
}

void 
CActivity::
Update()
{
  GetMainWindow()->Update();
}

void 
CActivity::
Exit()
{
  onPause();
  OnStop();
  OnDestroy();
}

//----------------------------------------------------
//Application. create all global variables, a first 
//activity, a input engine, a view Manager.
//----------------------------------------------------
class CApplication
{
  public:
    void ConstructL()
    {
      //input engine
      iInputEngine = CInputEngine::NewL();

      //graphics Context
      iGraphicContext = CGraphicContext::NewL();

      //activity manager 
      iActivityManager = CActivityManager::NewL();

      //set the activity Manager
      iActivityManager->SetInputEngine(iInputEngine);
      iActivityManager->SetGraphicsContext(iGraphicContext);
      iActivityManager->SetInitialActiviy(CActiviyMain::NewL());
    }

    void offerkeyevent(aevent)
    {
      getinput(aevent).dispatch(iactivitymanager);
    }

  private:
    void GetInput(EEvent& aEvent)
    {
      switch(aEvent.iType)
      {
        case EKeyboard:
          return EInputKeyboard(aEvent.iCode);

        case EScreen:
          return EInputScreen(aEvent.iCode);
      }
    }
};

//----------------------------------------------------
//Test
//----------------------------------------------------
void TestStartActivity()
{
  iActivityManager = CActiviyManager::NewL();

  CActivity* mainActivity = CActivity::NewL();

  iActivityManager->Destroy();
};

void
CWindow::
Update()
{
  for (TInt i = 0; i < iWidgetContainer.Count(); i++)
  {
    if (iWidgetContainer.IsDirty())
    {
      iWidgetContainer[i].Update(iGraphicsContext);
    }
  }
}

class CEditor : public View
{
  public:
    void SetFocused(TBool aFocus)
    {
      if (aFocus)
      {
        CGlobal::addToStack(iEditor);
      } else
      {
        CGlobal::RemoveFromStackL(iEditor);
      }
    }
};

class CViewList : public View
{
  public:
    void OnKeyOk();
}

bool 
CActivity::
onKeyEvent(aEvent)
{
  switch(aEvent.iType)
  {
    case EKeyOption:
      iKeyOption.Fire(aEvent);
      break;

    default:
      iKeyOther.Fire(aEvent);
      break;
  }
}

void
CActivity::
onOtherKey(aEvent)
{
  View& cView = CurrentView();

  if (!cView.onKeyDown())
  {
    onKeyDown();
  }
}

//the view can hand out its focused state, but cannot set by itself
//it'll hand to its parent.
void 
CWindow::
onFocusChange(View* aPreviousView)
{
  aPreviousView->SetFocused(EFalse);
  aPreviousView->onFoucusedChange();

  switch(aPreviousView->Id())
  {
    case EBottom:
      iTop->SetFocused(ETrue);
      break;

    case ETop:
      iBottom->SetFocused(ETrue);
      break;

    default:
      handleOutFocus(aPreviousView);
      break;
  }
  
  FocusedView()->onFocusedChange();
}

#endif
